/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.collections.tuples;

import com.softwarecraftsmen.collections.IndexExceedsHighestKnownIndexException;
import com.softwarecraftsmen.collections.IndexLessThanZeroException;
import com.softwarecraftsmen.collections.Key;
import static com.softwarecraftsmen.collections.tuples.EmptyTuple.emptyTuple;
import static com.softwarecraftsmen.collections.tuples.Pair.pair;
import static com.softwarecraftsmen.collections.tuples.Quadruple.quadruple;
import static com.softwarecraftsmen.collections.tuples.Quintuple.quintuple;
import static com.softwarecraftsmen.collections.tuples.Septuple.septuple;
import static com.softwarecraftsmen.collections.tuples.Sextuple.sextuple;
import static com.softwarecraftsmen.collections.tuples.Singleton.singleton;
import static com.softwarecraftsmen.collections.tuples.Triple.triple;
import static com.softwarecraftsmen.functors.Boolean.False;
import static com.softwarecraftsmen.functors.Boolean.fromLegacyBoolean;
import com.softwarecraftsmen.functors.Boolean;
import static com.softwarecraftsmen.functors.Boolean.True;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.LinkedList;

public abstract class AbstractTuple implements Tuple
{
	@NotNull
	public static EmptyTuple tuple()
	{
		return emptyTuple();
	}

	@NotNull
	public static <A> Singleton<A> tuple(@NotNull final A a)
	{
		return singleton(a);
	}

	@NotNull
	public static <A, B> Pair<A, B> tuple(@NotNull final A a, @NotNull final B b)
	{
		return pair(a, b);
	}

	@NotNull
	public static <A, B, C> Triple<A, B, C> tuple(@NotNull final A a, @NotNull final B b, @NotNull final C c)
	{
		return triple(a, b, c);
	}

	@NotNull
	public static <A, B, C, D> Quadruple<A, B, C, D> tuple(@NotNull final A a, @NotNull final B b, @NotNull final C c, @NotNull final D d)
	{
		return quadruple(a, b, c, d);
	}

	@NotNull
	public static <A, B, C, D, E> Quintuple<A, B, C, D, E> tuple(@NotNull final A a, @NotNull final B b, @NotNull final C c, @NotNull final D d, @NotNull final E e)
	{
		return quintuple(a, b, c, d, e);
	}

	@NotNull
	public static <A, B, C, D, E, F> Sextuple<A, B, C, D, E, F> tuple(@NotNull final A a, @NotNull final B b, @NotNull final C c, @NotNull final D d, @NotNull final E e, @NotNull final F f)
	{
		return sextuple(a, b, c, d, e, f);
	}

	@NotNull
	public static <A, B, C, D, E, F, G> Septuple<A, B, C, D, E, F, G> tuple(@NotNull final A a, @NotNull final B b, @NotNull final C c, @NotNull final D d, @NotNull final E e, @NotNull final F f, @NotNull final G g)
	{
		return septuple(a, b, c, d, e, f, g);
	}

	protected void guardValueAt(final int index)
	{
		if (index < 0)
		{
			throw new IndexLessThanZeroException(index);
		}
		if (index >= size())
		{
			throw new IndexExceedsHighestKnownIndexException(index);
		}
	}

	@NotNull
	public ArrayList<Object> toLegacyArrayList()
	{
		return new ArrayList<Object>(size());
	}

	@NotNull
	public LinkedList<Object> toLegacyLinkedList()
	{
		return new LinkedList<Object>();
	}

	@NotNull
	public Object[] toLegacyArray()
	{
		return toLegacyArrayList().toArray();
	}

	@NotNull
	public Boolean isMutable()
	{
		return False;
	}

	@NotNull
	public Boolean isEmpty()
	{
		return fromLegacyBoolean(size() == 0);
	}

	@NotNull
	public Boolean hasElements()
	{
		return fromLegacyBoolean(size() != 0);
	}

	@NotNull
	public abstract Object valueAt(final Integer key);

	public abstract int size();

	@NotNull
	public Boolean contains(final @NotNull Integer key)
	{
		return fromLegacyBoolean(key >= 0).and(fromLegacyBoolean(key < size()));
	}

	@NotNull
	public Boolean doesNotContain(final @NotNull Integer key)
	{
		return contains(key).not();
	}

	@NotNull
	public com.softwarecraftsmen.functors.Boolean isOrdered()
	{
		return True;
	}

	@NotNull
	public Boolean isSorted()
	{
		return True;
	}

	public Boolean isEqualTo(final @NotNull Key key)
	{
		return fromLegacyBoolean(equals(key));
	}

	public int computeHashCode()
	{
		return hashCode();
	}
}
